package xyz.eden.cloud.common.core.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * JsonToolByJackson
 */
@Slf4j
public class JsonToolByJackson {
    /**
     * 该 mapper 会将属性为 null 序列化
     */
    private static ObjectMapper mapper = null;
    /**
     * 该 mapper 会将属性为 null 不序列化
     */
    private static ObjectMapper mapperWithoutNull = null;

    public static <T> List<T> toJavaList(String json, Class<T> clazz) {
        if (StringUtils.isBlank(json)) {
            return Collections.emptyList();
        }
        try {
            ObjectMapper objectMapper = getInstance();
            return objectMapper.readValue(json, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
        } catch (Exception e) {
            return Collections.emptyList();
        }
    }

    public static <T> List<T> toJavaListWithException(String json, Class<T> clazz) throws Exception {
        if (StringUtils.isBlank(json)) {
            return Collections.emptyList();
        }
        ObjectMapper objectMapper = getInstance();
        return objectMapper.readValue(json, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
    }

    public static String toJsonStr(Object object) {
        return toJsonStr(object, true);
    }

    public static String toJsonStr(Object object, boolean containNull) {
        if (object == null) {
            return "";
        }
        try {
            return getInstance(containNull).writeValueAsString(object);
        } catch (Exception e) {
            log.info("toJsonStr exception", e);
            return "";
        }
    }

    public static <V> Map<String, V> toJavaMap(String json) {
        if (StringUtils.isBlank(json)) {
            return null;
        }
        return toJavaObj(json, new TypeReference<>() {
        });
    }

    public static <T> T toJavaObj(String json, TypeReference<T> typeRef) {
        if (typeRef == null)
            throw new NullPointerException("typeReference is null");
        try {
            Type type = typeRef.getType();
            return readValue(json, type);
        } catch (Exception e) {
            return null;
        }
    }

    public static <T> T toJavaObj(String json, Class<T> clazz) {
        try {
            return jsonToObjectThrowException(json, clazz);
        } catch (Exception e) {
            return null;
        }
    }

    public static <T> T jsonToObjectThrowException(String json, Class<T> clazz) throws Exception {
        return readValue(json, clazz);
    }

    private static <T> T readValue(String json, Type type) throws Exception {
        if (StringUtils.isBlank(json)) {
            return null;
        }
        ObjectMapper mapper = getInstance();
        TypeFactory typeFactory = mapper.getTypeFactory();
        JavaType javaType = typeFactory.constructType(type);
        return mapper.readValue(json, javaType);
    }

    /**
     * 默认初始化为包含 null
     *
     * @return
     */
    private static ObjectMapper getInstance() {
        // 默认情况都包含null
        return getInstance(true);
    }

    /**
     * 采用懒加载方式
     *
     * @param containsNull
     * @return
     */
    private static ObjectMapper getInstance(boolean containsNull) {
        ObjectMapper objectMapper = containsNull ? mapper : mapperWithoutNull;
        if (Objects.nonNull(objectMapper)) {
            return objectMapper;
        }

        synchronized (JsonToolByJackson.class) {
            if (Objects.nonNull(objectMapper)) {
                return objectMapper;
            }

            ObjectMapper commonMapper = getCommonMapper();
            if (!containsNull) {
                commonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            }
            return containsNull ? (mapper = commonMapper) : (mapperWithoutNull = commonMapper);
        }
    }

    private static ObjectMapper getCommonMapper() {
        ObjectMapper mapper = new ObjectMapper();
        // 注册 JDK LocalDateTime 处理模块
        mapper.registerModule(new JavaTimeModule());
        // 兼容性Feature配置
        mapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
        mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        mapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
        mapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        // 兼容性：忽略未知字段
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 注意，将时间序列化为类似“yyyy-MM-ddTHH:mm:ss.SSS+0000”的格式
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        // 注意，默认在序列化结果中输出值为null的字段
        return mapper;
    }
}
